package vinh.game;

import java.util.ArrayList;

import utils.Constants;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;

public class SpaceBlasterGame extends PersonalizedView{
	/**
	 * member variables
	 */
	Paint mWhitePaint;
	Paint mGreenPaint;
	Paint mRedPaint;
	Paint mBrownPaint;
	Paint mYellowPaint;
	Paint mOrangePaint;
	Context mContext; 
	int width = getWidth();
	int height = getHeight();

	boolean started = false;
	/**
	 * Game components
	 */
	Shuttle shuttle;
	
	Thruster forward_thruster;
	
	ArrayList<Shot> shots ; 
	
	ArrayList<Asteroid> asteroids;

	PolygonSprite bounds;
	
	Bitmap shuttle_bmp;
	Bitmap asteroid_bmp;
	Bitmap explosion_bmp;
	
	int num_stars;
	Point[] stars;
	
	int pos_x, pos_y;
	

	
	float dir_x = 0;
	float dir_y = 0;

	/**
	 * Set paint colors
	 */
	private void initLayout() {
		//set white paint
		mWhitePaint = new Paint();
		mWhitePaint.setARGB(255, 255, 255, 255);

		//set green paint
		mGreenPaint = new Paint();
		mGreenPaint.setARGB(255, 0, 255, 0);
		mGreenPaint.setStyle(Paint.Style.FILL);

		//set red paint
		mRedPaint = new Paint();
		mRedPaint.setARGB(255, 255, 0, 0);
		mRedPaint.setStyle(Paint.Style.FILL);

		mBrownPaint = new Paint();
		mBrownPaint.setARGB(255,139,119,101);
		mBrownPaint.setStyle(Paint.Style.FILL);
		mYellowPaint = new Paint();
		mYellowPaint.setARGB(255, 250,250,210);
		
		mOrangePaint = new Paint();
		mOrangePaint.setARGB(255,  243, 132, 0);
		
		shuttle_bmp = getImage(R.drawable.ship);
		asteroid_bmp = getImage(R.drawable.sb_meteor);
		explosion_bmp = getImage(R.drawable.sb_boom0);
	}
	
	/**
	 * Constructor
	 * setUpdatePeriod < ArcadeGame
	 */
	public SpaceBlasterGame(Context context) {
		super(context);
		mContext = context;
		setUpdatePeriod(Constants.DELAY);
		initLayout();
	}
	
	/**
	 * Constructor overload
	 * setUpdatePeriod < ArcadeGame
	 */
	public SpaceBlasterGame(Context context, AttributeSet attrs){
		super(context, attrs);
		mContext = context;
		setUpdatePeriod(Constants.DELAY);
		initLayout();
	}
/**
 * Creation phase, in other words, declaration of all the variables	
 */
	private void createBackground() {
		int width = getWidth();
		int height = getHeight();
		
		// Generate the starry background.
		num_stars = width * height / 5000;
		stars = new Point[num_stars];

		for (int i = 0; i < num_stars; i++)
			stars[i] = new Point((int) (Math.random() * width), (int) (Math.random() * height));
	}

	private void createShuttle(){
		shuttle = new Shuttle();
	}
	
	private void createThrusters(){
		forward_thruster = new Thruster(shuttle);

		forward_thruster.shape.addPoint(0, 12);
		forward_thruster.shape.addPoint(-3, 16);
		forward_thruster.shape.addPoint(0, 26);
		forward_thruster.shape.addPoint(3, 16);
	}
	
	private void createShots(){
		shots = new ArrayList<Shot>();
		initShots();
	}
	
	private void createAsteroids(){
		asteroids = new ArrayList<Asteroid>();
	}

	
	@Override
	protected void initialize() {
		createBackground();
		createShuttle();
		createThrusters();
		createShots();
		createAsteroids();
		initGame();
	}
	/**
	 * Initialisation phase, in other words, give first values to the variables
	 */
	private void initShuttle() {
		int width = getWidth();
		int height = getHeight();

		shuttle.init(width, height);

		shuttle.render();

		shuttle.active = true;
		
		forward_thruster.set_position();
		forward_thruster.render();
	}
	
	private void initShots() {

		for (Shot shot : shots)
			shot.active = true;
	}
	
	private void initAsteroids(){
		int width = getWidth();
		int height = getHeight();

		for (int i = 0; i < Asteroid.MAX; i++) {
			asteroids.add(new Asteroid());
		}
		
		for(Asteroid asteroid : asteroids){
			asteroid.active = true;
			asteroid.init(width, height);
			asteroid.render();
		}
	}
	
	private void initGame(){
		initShuttle();
		initShots();
		initAsteroids();

	}
	/**
	 * Drawing phase, automatically called
	 */
	@Override
	protected void onDraw(Canvas canvas) 
	{
		// draw stars
		for (int i = 0; i < num_stars; i++) {
			canvas.drawPoint(stars[i].x, stars[i].y, mWhitePaint);
		}
		
			canvas.save(Canvas.MATRIX_SAVE_FLAG);
			canvas.rotate((float)(-shuttle.angle/2/Math.PI*360), shuttle.x, shuttle.y);
			canvas.drawBitmap(shuttle_bmp, shuttle.x - shuttle_bmp.getWidth()/2, shuttle.y - shuttle_bmp.getHeight()/2, null);
			canvas.restore();
	
			Paint paint = new Paint();
			synchronized(shots){
				int i =0;
				for(Shot shot : shots){
					paint = mRedPaint;			
					if (i < 5) 
						paint = mYellowPaint;
					if (i >= 5 && i < 10)
						paint = mOrangePaint;
				
					synchronized(shot){
						shot.draw(canvas, paint);
					}
					i++;
				}
			}
			if (Math.random() < 0.5) { 
					forward_thruster.draw(canvas, mRedPaint);
			}
	
			// Draw the asteroids.
			synchronized(asteroids){
				for(Asteroid asteroid : asteroids){
					synchronized(asteroid){
						if(asteroid.active){
//							asteroid.draw(canvas, mBrownPaint);
							canvas.save(Canvas.MATRIX_SAVE_FLAG);
							canvas.rotate((float)(-asteroid.angle/2/Math.PI*360), asteroid.x, asteroid.y);
							canvas.drawBitmap(asteroid_bmp, asteroid.x - asteroid_bmp.getWidth()/2, asteroid.y - asteroid_bmp.getHeight()/2, null);
							canvas.restore();
						}
					}
				}
			}
	}
	
	/**
	 * Update phase, called by the timer, redefines behavior and state of the variables.
	 * Use of synchronized on the lists because concurrency with the thread onDraw, for the view
	 */
	private void updateShuttle(){
		int width = getWidth();
		int height = getHeight();
		
		if(dir_x != 0 || dir_y != 0){
			
			shuttle.angle = Math.atan2(-(dir_y - shuttle.y), dir_x - shuttle.x) - Math.PI/2;
			shuttle.delta_angle = 0;

			dir_x = 0;
			dir_y = 0;
		}
		
		shuttle.delta_x = Math.round(shuttle.speed * Math.cos(shuttle.angle + Math.PI/2) );
		shuttle.delta_y = Math.round(shuttle.speed * Math.sin(shuttle.angle + Math.PI/2) );
		shuttle.advance(width, height, shuttle.speed);
		shuttle.render();
	}

	private void updateAsteroids(){
		int width = getWidth();
		int height = getHeight();

		synchronized(asteroids){
			for(Asteroid asteroid : asteroids){
				synchronized(shots){
	
					for(Shot shot : shots){
						if(asteroid.isColliding(shot))
							asteroid.init(width, height);

						if(asteroid.isColliding(shuttle))
							started = false;
					}
				
				}
				synchronized(asteroid){
					asteroid.advance(width, height, asteroid.speed());
					asteroid.render();
				}
			}
		}
	}
	
	int shotCounter=0;
	private void updateShots(){
		int width = getWidth();
		int height = getHeight();
		if(shots.size() > Shot.MAX){
			synchronized(shots){
				synchronized(shots.get(0)){
					shots.remove(0);
				}
			}
		}else{
			if((shotCounter%10) == 0){
				Shot shot = new Shot(shuttle.angle, shuttle.x, shuttle.y);
				shot.active = true;
				synchronized(shots){
					shots.add(shot);
				}
				shotCounter=0;
			}
		}
		shotCounter++;

		for(int i = 0 ; i < shots.size()-1 ; i++ ){
			shots.get(i).advance(width, height, shots.get(i).speed);
			shots.get(i).render();
		}
		
	}
	
	private void updateThruster(){
		forward_thruster.set_position(shuttle.angle, shuttle.x, shuttle.y);
		forward_thruster.render();
	}

	@Override
	protected void updatePhysics() {
			updateShuttle();
			updateShots();
			updateAsteroids();
			updateThruster();
	}
	
	public boolean onTouchEvent(MotionEvent event){
			dir_x = event.getX();
			dir_y = event.getY();
		return true;
	}
	
	
	@Override
	protected void kill(){
		shuttle = null;
		forward_thruster = null;
		asteroids = null;
		shots = null;
	}

}
